﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Runtime.Serialization.Json;

namespace Batch_Disc_Backup
{
    /// <summary>
    /// Contains the methods for saving and writing the log files of the disc copys.
    /// Each log file is stored under:
    ///     &lt;Application dir&gt;\logs\&lt;Log date&gt;\&lt;Log date and time&gt; - &lt;Volume label&gt;.json
    /// </summary>
    public static class Log
    {
        /// <summary>
        /// Gets the directory of where the logs are stored
        /// </summary>
        /// <returns></returns>
        public static string GetLogRootDir()
        {
            return Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "logs");
        }

        /// <summary>
        /// Gets the directory of where the logs are stored for a specific date
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string GetLogDir(DateTime date)
        {
            return Path.Combine(GetLogRootDir(), date.ToString("yyyy-MM-dd"));
        }

        /// <summary>
        /// Gets the dates of when logs were made. This is retreived by simple grabbing the
        /// directory list from the log directory, and parsing the names as DateTime objects.
        /// </summary>
        /// <returns></returns>
        public static List<DateTime> GetLogDates()
        {
            List<DateTime> ret = new List<DateTime>();
            string dir = GetLogRootDir();
            if (!Directory.Exists(dir))
                return ret;

            string[] dirs = Directory.GetDirectories(dir);
            string[] split;
            for (int i = 0; i < dirs.Length; i++)
            {
                split = Path.GetFileName(dirs[i]).Split(new char[] { '-' });
                if (split.Length != 3) continue;
                try
                {
                    ret.Add(new DateTime(Int32.Parse(split[0]), Int32.Parse(split[1]), Int32.Parse(split[2])));
                }
                catch { } //Just go to the next directory
            }
            return ret;
        }

        /// <summary>
        /// Writes the log to disc. I understand that writing logs files as json objects
        /// is very stupid as it would be costly to rewrite live log updates, but it
        /// was the quickest way to do it, and I made the decision to only write a log for
        /// each process twice; once when it starts, and then it is overwritten once the
        /// process completes.
        /// </summary>
        /// <param name="dci"></param>
        public static void Write(DiscCopyInfo dci)
        {
            //Create the log directory
            string logDir = GetLogDir((DateTime)dci.DateStarted);
            try {
                if (!Directory.Exists(logDir)) Directory.CreateDirectory(logDir);
            } catch (Exception ex) {
                return;
            }
            //Get the filename of the log file
            string fullFilename = null;
            if (dci.LogFilename == null) //If it hasn't been set yet, create it
            {
                fullFilename = Quick.NextFilename(Path.Combine(logDir, (((DateTime)dci.DateStarted).ToString("yyyy-MM-dd HH.mm.ss") + " - " + dci.VolumeLabel + ".json")));
                dci.LogFilename = Path.GetFileName(fullFilename);
            }
            else
            {
                fullFilename = Path.Combine(logDir, dci.LogFilename);
            }
            //Convert the DiscCopyInfo object to json, and write it to disc.
            //Overwrite any file that is already there
            try {
                DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(DiscCopyInfo));
                using (MemoryStream ms = new MemoryStream()) {
                    ser.WriteObject(ms, dci);
                    using (StreamReader reader = new StreamReader(ms)) {
                        ms.Position = 0;
                        using (StreamWriter writer = new StreamWriter(fullFilename, false)) {
                            writer.Write(reader.ReadToEnd());
                        }
                    }
                }
            } catch (Exception ex) {
            }
        }

        /// <summary>
        /// Retreivs all of the logged DiscCopyInfos for a specific date.
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static List<DiscCopyInfo> GetDiscCopyInfos(DateTime date)
        {
            List<DiscCopyInfo> infos = new List<DiscCopyInfo>();
            string dir = GetLogDir(date);
            if (!Directory.Exists(dir)) return infos;

            string[] files = null;
            try
            {
                files = Directory.GetFiles(dir);
            }
            catch
            {
                return infos;
            }
            foreach (string file in files) {
                try {
                    using (StreamReader reader = new StreamReader(file))
                    {
                        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(DiscCopyInfo));
                        using (MemoryStream ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(reader.ReadToEnd())))
                        {
                            ms.Position = 0;
                            infos.Add((DiscCopyInfo)ser.ReadObject(ms));
                        }
                    }
                }
                catch
                {
                }
            }
            return infos;
        }

        /// <summary>
        /// Deletes all logs
        /// </summary>
        public static void DeleteLogs()
        {
            string[] dirs = Directory.GetDirectories(GetLogRootDir());
            DeleteLogs(dirs);
        }
        /// <summary>
        /// Deletes all logs for a specific date
        /// </summary>
        /// <param name="dateTime"></param>
        public static void DeleteLogs(DateTime dateTime)
        {
            string[] dirs = Directory.GetDirectories(GetLogRootDir());
            DeleteLogs(new string[] { GetLogDir(dateTime) });
        }

        /// <summary>
        /// Called by DeleteLogs() and DeleteLogs(DateTime dateTime) to actually delete the logs
        /// </summary>
        /// <param name="dirs"></param>
        private static void DeleteLogs(string[] dirs)
        {
            foreach (string dir in dirs)
            {
                string[] files = Directory.GetFiles(dir);
                foreach (string file in files)
                {
                    if (".json".Equals(Path.GetExtension(file), StringComparison.OrdinalIgnoreCase))
                        File.Delete(file);
                }
                if (Directory.GetFiles(dir).Length == 0)
                    Directory.Delete(dir);
            }
        }
    }
}
